package com.yonyou.distribute.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;

/**
 * p25  redis 分布式锁简单实现
 */
@Slf4j
@Service
public class RedisService_3 {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 解决超卖
     */
    public void deduct2() {
        // 加锁
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "111");
        if(!lock){
            //递归调用   有可能导致栈溢出，改成循环
            try{
                Thread.sleep(50);
                this.deduct();
            }catch (Exception e){
                e.printStackTrace();
            }
        }else{
            try{
                // 1、查询库存
                String stock = stringRedisTemplate.opsForValue().get("stock").toString();
                // 2、判断库存是否充足
                if(!StringUtils.isEmpty(stock)){
                    Integer st = Integer.valueOf(stock);
                    if(st > 0){
                        //3、更新库存到数据库
                        stringRedisTemplate.opsForValue().set("stock", String.valueOf(--st));

                    }
                }
            }finally {
                //解锁
                this.stringRedisTemplate.delete("lock");
            }
        }
    }

    /**
     * 递归调用，改成循环调用
     * 这样写还会有些问题
     * 1、防止死锁发生
     * 2、
     */
    public void deduct() {
        // 加锁
        while (!this.stringRedisTemplate.opsForValue().setIfAbsent("lock", "111")){// 这里获取锁之后，宕机了 解决：设置过期时间
            // 循环重试
            try{
                Thread.sleep(50);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        // 这时候获取到锁的服务宕机
        try{
            // 1、查询库存
            String stock = stringRedisTemplate.opsForValue().get("stock").toString();
            // 2、判断库存是否充足
            if(!StringUtils.isEmpty(stock)){
                Integer st = Integer.valueOf(stock);
                if(st > 0){
                    //3、更新库存到数据库
                    stringRedisTemplate.opsForValue().set("stock", String.valueOf(--st));
                }
            }
        }finally {
            //解锁 这里也会有问题，删除的是别人的锁  因为自己的锁已经时间到自动删除了
            this.stringRedisTemplate.delete("lock");
        }
    }

}
